package com.hibernate.rcache.region;

import com.hibernate.rcache.RcacheAccessStrategyFactory;
import com.rcache.core.Element;
import com.rcache.core.cache.Rcache;
import com.rcache.core.exception.RCacheException;
import com.rcache.core.manager.CacheManager;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.EntityRegion;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cfg.Settings;

import java.util.Map;
import java.util.Properties;

public class RcacheEntityRegion implements EntityRegion {

    private final CacheManager cacheManager;
    private final Rcache rcache;
    private final CacheDataDescription metadata;
    private final Settings settings;
    private final Properties properties;
    RcacheAccessStrategyFactory accessStrategyFactory=new RcacheAccessStrategyFactory();

    public RcacheEntityRegion(CacheManager cacheManager, Rcache rcache, Properties properties, Settings settings, CacheDataDescription metadata){
        this.cacheManager=cacheManager;
        this.rcache=rcache;
        this.metadata=metadata;
        this.settings=settings;
        this.properties=properties;
    }

    public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {


        return accessStrategyFactory.createEntityRegionAccessStrategy( this, accessType );
    }

    public boolean isTransactionAware() {
        return false;
    }

    public CacheDataDescription getCacheDataDescription() {
        return metadata;
    }

    public String getName() {
        return rcache.getCacheName();
    }

    public void destroy() throws CacheException {
        cacheManager.remove(rcache.getCacheName());
    }

    public boolean contains(Object key) {
        return rcache.containsKey(key);
    }

    public long getSizeInMemory() {
        return 0;
    }

    public long getElementCountInMemory() {
        return 0;
    }

    public long getElementCountOnDisk() {
        return 0;
    }

    public Map toMap() {
        return rcache.toMap();
    }

    public long nextTimestamp() {
        return 0;
    }

    public int getTimeout() {
        return 0;
    }

    public CacheDataDescription getMetadata() {
        return metadata;
    }

    public Settings getSettings() {
        return settings;
    }

    public Object get(Object key) {
        try {
            Element el = rcache.get(key);
            if (el==null){
                return null;
            }else{
                return el.getObjectValue();
            }
        } catch (Exception e) {

            return null;
        }
    }

    public void put(Object key, Object value) {
        rcache.put(key,value);
    }

    public void remove(Object key) {
        rcache.remove(key);
    }

    public void clear() {
        rcache.clear();
    }

    public void writeLock(Object key) {
        long old = rcache.get(key).getVersion();
        Element value = rcache.get(key);
        rcache.put(key+"lock",value);
        rcache.get(key+"lock").setVersion(old+1);

    }

    public void putandlock(Object key, Object value) {

        Element cache = rcache.get(key);
        long old = cache.getVersion();
        Element lockcache = rcache.get(key + "lock");
        if (old<lockcache.getVersion()){
            cache.setObjectValue(value);
            cache.setVersion(old+1);
            rcache.put(key,cache);

        }else {
            rcache.put(key,lockcache.getObjectValue());
        }
    }

    public void writeUnlock(Object key) {
        rcache.remove(key+"lock");
    }
}
